package com.quanz.ckgl.services.jpa;

import static org.springframework.data.querydsl.QueryDslUtils.QUERY_DSL_PRESENT;

import java.io.Serializable;

import javax.persistence.EntityManager;

import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.support.JpaEntityInformation;
import org.springframework.data.jpa.repository.support.JpaRepositoryFactory;
import org.springframework.data.jpa.repository.support.QueryDslJpaRepository;
import org.springframework.data.jpa.repository.support.SimpleJpaRepository;
import org.springframework.data.querydsl.QueryDslPredicateExecutor;
import org.springframework.data.repository.core.RepositoryMetadata;

/**
 * {@link GenericRepository}的缺省实现
 * @author James Quan
 * @version 2015年10月5日 上午10:20:58
 */
public class GenericRepositoryFactory extends JpaRepositoryFactory {

	public GenericRepositoryFactory(EntityManager entityManager) {
		super(entityManager);
	}

	@Override
	@SuppressWarnings({ "unchecked", "rawtypes" })
	protected <T, ID extends Serializable> SimpleJpaRepository<?, ?> getTargetRepository(
			RepositoryMetadata metadata, EntityManager entityManager) {

		Class<?> repositoryInterface = metadata.getRepositoryInterface();
		JpaEntityInformation<?, Serializable> entityInformation = getEntityInformation(metadata.getDomainType());
		SimpleJpaRepository<?, ?> repo = isQueryDslExecutor(repositoryInterface) ? new QueryDslGenericRepositoryImpl(
				entityInformation, entityManager) : new GenericRepositoryImpl(
				entityInformation, entityManager);		
		return repo;
	}

	@Override
	protected Class<?> getRepositoryBaseClass(RepositoryMetadata metadata) {
		if (isQueryDslExecutor(metadata.getRepositoryInterface())) {
			return QueryDslGenericRepositoryImpl.class;
		} else {
			return GenericRepositoryImpl.class;
		}
	}

	/**
	 * Returns whether the given repository interface requires a QueryDsl
	 * specific implementation to be chosen.
	 * 
	 * @param repositoryInterface
	 * @return
	 */
	private boolean isQueryDslExecutor(Class<?> repositoryInterface) {

		return QUERY_DSL_PRESENT
				&& QueryDslPredicateExecutor.class
						.isAssignableFrom(repositoryInterface);
	}
}